import { Context, Next } from 'koa';
import { logger } from '@/utils/logger';
import { ResponseUtil } from '@/utils/response';

/**
 * 自定义错误类
 */
export class AppError extends Error {
  public statusCode: number;
  public isOperational: boolean;

  constructor(message: string, statusCode: number = 500) {
    super(message);
    this.statusCode = statusCode;
    this.isOperational = true;

    Error.captureStackTrace(this, this.constructor);
  }
}

/**
 * 全局错误处理中间件
 */
export const errorHandler = async (ctx: Context, next: Next): Promise<void> => {
  try {
    await next();
  } catch (error) {
    let statusCode = 500;
    let message = '服务器内部错误';

    // 处理已知错误
    if (error instanceof AppError) {
      statusCode = error.statusCode;
      message = error.message;
    } else if (error instanceof Error) {
      // 处理 Joi 验证错误
      if (error.name === 'ValidationError') {
        statusCode = 400;
        message = error.message;
      }
      // 处理 JWT 错误
      else if (error.name === 'JsonWebTokenError') {
        statusCode = 401;
        message = '无效的令牌';
      } else if (error.name === 'TokenExpiredError') {
        statusCode = 401;
        message = '令牌已过期';
      }
      // 处理 MongoDB 错误
      else if (error.name === 'MongoError' || error.name === 'MongooseError') {
        statusCode = 500;
        message = '数据库操作失败';
      }
      // 处理 MySQL 错误
      else if (error.message?.includes('ER_')) {
        statusCode = 500;
        message = '数据库操作失败';
      }
      // 其他错误
      else {
        message = error.message || message;
      }
    }

    // 记录错误日志
    logger.error({
      error: {
        message: error instanceof Error ? error.message : String(error),
        stack: error instanceof Error ? error.stack : undefined,
        statusCode,
      },
      request: {
        method: ctx.method,
        url: ctx.url,
        headers: ctx.headers,
        body: ctx.request.body,
        query: ctx.query,
        params: ctx.params,
      },
    }, '请求处理错误');

    // 设置响应状态和内容
    ctx.status = statusCode;
    ctx.body = ResponseUtil.error(message, statusCode, ctx.path);

    // 在开发环境中添加错误堆栈信息
    if (process.env.NODE_ENV === 'development' && error instanceof Error) {
      (ctx.body as any).stack = error.stack;
    }
  }
};

/**
 * 404 错误处理中间件
 */
export const notFoundHandler = async (ctx: Context, next: Next): Promise<void> => {
  await next();

  if (ctx.status === 404 && !ctx.body) {
    ctx.status = 404;
    ctx.body = ResponseUtil.notFound(`路由 ${ctx.path} 不存在`);
  }
};

export default errorHandler;